/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package dota2patcher;

import java.awt.Color;
import java.io.File;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JFileChooser;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.StyleConstants;
import com.jidesoft.plaf.LookAndFeelFactory;
import java.awt.Container;
import java.awt.Image;
import java.awt.Toolkit;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.concurrent.ExecutionException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JScrollBar;
import javax.swing.SwingWorker;
import javax.swing.UIManager;
import javax.swing.tree.TreeNode;
import javax.swing.tree.TreePath;
import vpkmanager.VpkManager;
 

/**
 *
 * @author maz
 */
public class Dota2PatcherUI extends javax.swing.JFrame {
   
    /**
     * Creates new form Dota2PatcherUI
     */
    public Dota2PatcherUI() {
        initComponents();
        init();
    }
    
    Dota2Patcher dp = new Dota2Patcher();
    VpkManager vpk;
    FileTreeNode rootTreeNode = new FileTreeNode(new File("C:\\"), true, null);
    Boolean debug;
    String vpk_path;
    String mod_path;
    Boolean patchAll = false;
    ArrayList<String> patchedFiles  = new ArrayList<>();
    ArrayList<String> files = new ArrayList<>();

    /**
     * This method is called from within the constructor to initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is always
     * regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        jButtonPatch = new javax.swing.JButton();
        jButtonExit = new javax.swing.JButton();
        jProgressBar = new javax.swing.JProgressBar();
        jTextDota2Path = new javax.swing.JTextField();
        jButtonDota2Path = new javax.swing.JButton();
        jLabelTop = new javax.swing.JLabel();
        jLabelDota2Path = new javax.swing.JLabel();
        jLabel1 = new javax.swing.JLabel();
        jSplitPane2 = new javax.swing.JSplitPane();
        jScrollPaneOutput = new javax.swing.JScrollPane();
        jTextPaneOutput = new javax.swing.JTextPane();
        jScrollPaneTree = new javax.swing.JScrollPane();
        checkBoxTree = new com.jidesoft.swing.CheckBoxTree(rootTreeNode);
        jButtonClear = new javax.swing.JButton();
        jCheckBoxDebug = new javax.swing.JCheckBox();
        jTextFieldVPKPath = new javax.swing.JTextField();
        jLabel2 = new javax.swing.JLabel();
        jButtonVpkPath = new javax.swing.JButton();
        jButtonHelp = new javax.swing.JButton();
        jButtonForce = new javax.swing.JButton();

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        setTitle("Dota2Patcher");

        jButtonPatch.setText("Patch");
        jButtonPatch.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButtonPatchActionPerformed(evt);
            }
        });

        jButtonExit.setText("Exit");
        jButtonExit.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButtonExitActionPerformed(evt);
            }
        });

        jTextDota2Path.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jTextDota2PathActionPerformed(evt);
            }
        });

        jButtonDota2Path.setText("Browse...");
        jButtonDota2Path.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButtonDota2PathActionPerformed(evt);
            }
        });

        jLabelTop.setFont(new java.awt.Font("Tahoma", 0, 24)); // NOI18N
        jLabelTop.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
        jLabelTop.setText("Dota2Patcher");

        jLabelDota2Path.setText("Dota2 Path:");

        jLabel1.setText("Select files to patch:");

        jSplitPane2.setDividerLocation(300);

        jTextPaneOutput.setEditable(false);
        jTextPaneOutput.setBackground(new java.awt.Color(240, 240, 240));
        jTextPaneOutput.setContentType("text/html"); // NOI18N
        jScrollPaneOutput.setViewportView(jTextPaneOutput);

        jSplitPane2.setRightComponent(jScrollPaneOutput);

        checkBoxTree.setCellRenderer(new FileTreeCellRenderer());
        jScrollPaneTree.setViewportView(checkBoxTree);

        jSplitPane2.setLeftComponent(jScrollPaneTree);

        jButtonClear.setText("Clear");
        jButtonClear.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButtonClearActionPerformed(evt);
            }
        });

        jCheckBoxDebug.setText("Debug?");
        jCheckBoxDebug.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jCheckBoxDebugActionPerformed(evt);
            }
        });

        jTextFieldVPKPath.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jTextFieldVPKPathActionPerformed(evt);
            }
        });

        jLabel2.setText("VPK Path:");

        jButtonVpkPath.setText("Browse...");
        jButtonVpkPath.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButtonVpkPathActionPerformed(evt);
            }
        });

        jButtonHelp.setText("Help");
        jButtonHelp.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButtonHelpActionPerformed(evt);
            }
        });

        jButtonForce.setForeground(new java.awt.Color(153, 0, 0));
        jButtonForce.setText("FORCE PATCH");
        jButtonForce.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButtonForceActionPerformed(evt);
            }
        });

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(jLabelTop, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(jProgressBar, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                    .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                        .addComponent(jButtonExit)
                        .addGap(18, 18, 18)
                        .addComponent(jButtonClear)
                        .addGap(18, 18, 18)
                        .addComponent(jButtonHelp)
                        .addGap(18, 18, 18)
                        .addComponent(jCheckBoxDebug)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                        .addComponent(jButtonForce)
                        .addGap(18, 18, 18)
                        .addComponent(jButtonPatch))
                    .addComponent(jSplitPane2)
                    .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                            .addComponent(jTextDota2Path, javax.swing.GroupLayout.Alignment.TRAILING)
                            .addComponent(jTextFieldVPKPath, javax.swing.GroupLayout.Alignment.TRAILING)
                            .addGroup(layout.createSequentialGroup()
                                .addComponent(jLabel1)
                                .addGap(0, 0, Short.MAX_VALUE)))
                        .addGap(18, 18, 18)
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                            .addComponent(jButtonDota2Path)
                            .addComponent(jButtonVpkPath, javax.swing.GroupLayout.Alignment.TRAILING)))
                    .addGroup(layout.createSequentialGroup()
                        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                            .addComponent(jLabelDota2Path)
                            .addComponent(jLabel2))
                        .addGap(0, 931, Short.MAX_VALUE)))
                .addContainerGap())
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addComponent(jLabelTop)
                .addGap(1, 1, 1)
                .addComponent(jLabelDota2Path)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(jButtonDota2Path)
                    .addComponent(jTextDota2Path, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(jLabel2)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(jTextFieldVPKPath, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(jButtonVpkPath))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(jLabel1)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                .addComponent(jSplitPane2, javax.swing.GroupLayout.PREFERRED_SIZE, 423, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(jProgressBar, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addGap(4, 4, 4)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(jButtonPatch)
                    .addComponent(jButtonExit)
                    .addComponent(jButtonClear)
                    .addComponent(jCheckBoxDebug)
                    .addComponent(jButtonHelp)
                    .addComponent(jButtonForce))
                .addContainerGap())
        );

        pack();
    }// </editor-fold>//GEN-END:initComponents

    private void jButtonDota2PathActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButtonDota2PathActionPerformed
        JFileChooser chooser = new JFileChooser();
        chooser.setCurrentDirectory(new java.io.File("."));
        chooser.setDialogTitle("Select your dota2/dota directory");
        chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
        chooser.setAcceptAllFileFilterUsed(false);
        int rVal = chooser.showOpenDialog(null);
        if (rVal == JFileChooser.APPROVE_OPTION) {
          jTextDota2Path.setText(chooser.getSelectedFile().toString());
          updateTreePath();
        }
    }//GEN-LAST:event_jButtonDota2PathActionPerformed

    private void jButtonPatchActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButtonPatchActionPerformed
        patch();
    }//GEN-LAST:event_jButtonPatchActionPerformed

    private void jTextDota2PathActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jTextDota2PathActionPerformed
        updateTreePath();
    }//GEN-LAST:event_jTextDota2PathActionPerformed

    private void jButtonExitActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButtonExitActionPerformed
        Container master = jButtonExit.getParent();
        do {
            master = master.getParent();
        } while (!(master instanceof JFrame));                                      
        ((JFrame) master).dispose();
    }//GEN-LAST:event_jButtonExitActionPerformed

    private void jButtonClearActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButtonClearActionPerformed
        clear();
    }//GEN-LAST:event_jButtonClearActionPerformed

    private void jCheckBoxDebugActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jCheckBoxDebugActionPerformed
        debug = jCheckBoxDebug.isSelected();
        redirectSystemStreams();
    }//GEN-LAST:event_jCheckBoxDebugActionPerformed

    private void jButtonVpkPathActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButtonVpkPathActionPerformed
        JFileChooser chooser = new JFileChooser();
        chooser.setCurrentDirectory(new java.io.File("."));
        chooser.setDialogTitle("Select your dota2/dota directory");
        chooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
        chooser.setAcceptAllFileFilterUsed(false);
        int rVal = chooser.showOpenDialog(null);
        if (rVal == JFileChooser.APPROVE_OPTION) {
          jTextFieldVPKPath.setText(chooser.getSelectedFile().toString());
          updateVpk(1);
        }
    }//GEN-LAST:event_jButtonVpkPathActionPerformed

    private void jTextFieldVPKPathActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jTextFieldVPKPathActionPerformed
        updateVpk(1);
    }//GEN-LAST:event_jTextFieldVPKPathActionPerformed

    private void jButtonHelpActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButtonHelpActionPerformed
        clear();
        ArrayList<String> help = dp.getHelp();
        for (String line : help)
            log(line);
    }//GEN-LAST:event_jButtonHelpActionPerformed

    private void jButtonForceActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButtonForceActionPerformed
        File file = new File(vpk_path);
        String msg = ("You sure?\n Only run this if dota2 just got updated.");
        int dialogButton = JOptionPane.YES_NO_OPTION;
        int dialogResult = JOptionPane.showConfirmDialog(this, msg, "Forserious?",dialogButton);
        if(dialogResult==0) {
            logColor("FORCE PATCHING...");
            logColor("Removing VPK...");
            File bak = new File(vpk_path+".orig");
            bak.delete();
            patchAll = true;
            patch();
        }
    }//GEN-LAST:event_jButtonForceActionPerformed
   
    protected void revertVpk(int status) {
        File orig = new File(vpk_path);
        File bak = new File(vpk_path+".orig");
        if (!bak.isFile()) {
            logError("Could not find backup, your SOL.");
        } else {
            orig.delete();
            bak.renameTo(orig);
            if (status == 1) {
                logBlue("VPK Reverted!");
            }
        }
        updateVpk(status);
        patchAll = true;
    }
    
    protected void patch() {
        updateVpk(1);
        populateFiles();
        Patch p = new Patch();
        p.execute();
    }
    protected void populateFiles() {
        files.clear();
        TreePath[] treePaths = checkBoxTree.getCheckBoxTreeSelectionModel().getSelectionPaths();
        File tmp;
        if (treePaths != null) {
            for (TreePath path : treePaths) {
                tmp = new File(path.getLastPathComponent().toString());
                if (!tmp.isDirectory()) {
                    files.add(tmp.toString());
                } else {
                    try {
                        new FileTraversal() {
                            public void onFile( final File f ) {
                                files.add(f.toString());
                            }
                        }.traverse(tmp);
                    } catch (IOException ex) {
                        Logger.getLogger(Dota2PatcherUI.class.getName()).log(Level.SEVERE, null, ex);
                    }
                }
            }
        }
    }
   
    protected void clear() {
        updateProgressBar(0);
        jTextPaneOutput.setText("");
    }         
    
    public void log(String txt, SimpleAttributeSet att, Boolean newLine) {
        try {
            Document doc = jTextPaneOutput.getStyledDocument();
            JScrollBar vertical = jScrollPaneOutput.getVerticalScrollBar();
            vertical.setValue(vertical.getMaximum());
            if (newLine) {
                doc.insertString(doc.getLength(), txt + "\n", att);
            } else {
                doc.insertString(doc.getLength(), txt, att);
            }
        } catch (BadLocationException ex) {
            Logger.getLogger(Dota2PatcherUI.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
    
    public void log(String txt) {
       log(txt, null, true);
    }
    
    protected void logColor(String txt) {
        SimpleAttributeSet att = new SimpleAttributeSet();
        StyleConstants.setForeground(att, Color.MAGENTA);
        log(txt, att, true);
    }
    
    protected void logBlue(String txt) {
        SimpleAttributeSet att = new SimpleAttributeSet();
        StyleConstants.setForeground(att, Color.BLUE);
        log(txt, att, true);
    }
    
    protected void logError(String txt) {
        SimpleAttributeSet att = new SimpleAttributeSet();
        StyleConstants.setForeground(att, Color.RED);
        log("[ERROR]" + txt, att, true);
    }
    
    protected void logBold(String txt) {
        SimpleAttributeSet att = new SimpleAttributeSet();
        StyleConstants.setBold(att, true);
        log(txt, att, true);
    }
    
    public void logSystem(String txt) {
       log(txt, null, false);
    }
    
    private void init(){
        updateIcon();
        jTextDota2Path.setText(dp.dota2Path());
        mod_path = jTextDota2Path.getText();
        jTextFieldVPKPath.setText(dp.vpkPath()); 
        vpk_path = jTextFieldVPKPath.getText();
        updateTreePath();
        loadTreePaths();
        jButtonPatch.requestFocusInWindow();
        checkBoxTree.getCheckBoxTreeSelectionModel().addTreeSelectionListener(null);
    }
    
    protected void updateIcon() {
        //setIconImage(Toolkit.getDefaultToolkit().getImage(getClass().getResource("dota_2_hq.png")));
    }
    
    protected void updateTreePath(){
        mod_path = jTextDota2Path.getText();
        rootTreeNode.setRoot(mod_path);
        checkBoxTree.getCheckBoxTreeSelectionModel().clearSelection();
        checkBoxTree.updateUI();
    }
    
    protected void updateTreeUI(){
        checkBoxTree.updateUI();        
        TreePath[] save = checkBoxTree.getCheckBoxTreeSelectionModel().getSelectionPaths();
        List<TreePath> build = new ArrayList<TreePath>();
        int row;
        for (TreePath path : save) {
                row = checkBoxTree.getRowForPath(path);
                build.add(checkBoxTree.getPathForRow(row));
        }
        checkBoxTree.getCheckBoxTreeSelectionModel().clearSelection();
        for (TreePath path : build) {
            checkBoxTree.scrollPathToVisible(path);
            checkBoxTree.getCheckBoxTreeSelectionModel().addSelectionPath(path);
        }
    }
    
    protected void loadTreePaths() {
        File backup = new File(mod_path + "\\d2pTreePaths");
        if (backup.isFile()) {
            patchedFiles = (ArrayList<String>)dp.readObject(mod_path + "\\d2pTreePaths");

            ArrayList<FileTreeNode> fileNodes = new ArrayList<>();
            fileNodes = rootTreeNode.getFileNodes(fileNodes, rootTreeNode);
                for (FileTreeNode file : fileNodes) {
                    if (patchedFiles.contains(file.toString())) {
                        checkBoxTree.getCheckBoxTreeSelectionModel().addSelectionPath(rootTreeNode.getTreePath(file));
                        checkBoxTree.scrollPathToVisible(rootTreeNode.getTreePath(file));
                    }
                }
            updateTreeUI();
        }
    }

    protected void saveTreePaths() {
        TreePath[] treePaths = checkBoxTree.getCheckBoxTreeSelectionModel().getSelectionPaths();
        ArrayList<String> files = new ArrayList<>();
        for (TreePath path : treePaths) {
            files.add(path.getLastPathComponent().toString());
        }
        dp.saveObject(files, mod_path + "\\d2pTreePaths");
    }

    
    protected void updateProgressBar(int value) {
        if (value > 0) {
            jProgressBar.setStringPainted(true);
        } else {
            jProgressBar.setStringPainted(false);
        }
        jProgressBar.setValue(value);

    }
    
    protected void updateVpk(int status) {
        jButtonPatch.setEnabled(false);
        vpk_path = jTextFieldVPKPath.getText();
        VpkManagerWorker refresh = new VpkManagerWorker(status);
        refresh.execute();
        while (refresh.isDone() == false) {}
        try {
            vpk = refresh.get();
            jButtonPatch.setEnabled(true);
        } catch (InterruptedException ex) {
            Logger.getLogger(Dota2PatcherUI.class.getName()).log(Level.SEVERE, null, ex);
        } catch (ExecutionException ex) {
            Logger.getLogger(Dota2PatcherUI.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
    
    private void redirectSystemStreams() {
        OutputStream out = new OutputStream() {
            @Override
            public void write(final int b) throws IOException {
              logSystem(String.valueOf((char) b));
            }

            @Override
            public void write(byte[] b, int off, int len) throws IOException {
              logSystem(new String(b, off, len));
            }

            @Override
            public void write(byte[] b) throws IOException {
              write(b, 0, b.length);
            }
        };
        System.setOut(new PrintStream(out, true));
        System.setErr(new PrintStream(out, true));
    }
    
    /**
     * @param args the command line arguments
     */
    public static void main(String args[]) {
        /* Set the Nimbus look and feel */
        //<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
        /* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel.
         * For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html 
         */
        try {
            for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
                if ("Nimbus".equals(info.getName())) {
                    javax.swing.UIManager.setLookAndFeel(info.getClassName());
                    break;
                }
            }
        } catch (ClassNotFoundException ex) {
            java.util.logging.Logger.getLogger(Dota2PatcherUI.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (InstantiationException ex) {
            java.util.logging.Logger.getLogger(Dota2PatcherUI.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (IllegalAccessException ex) {
            java.util.logging.Logger.getLogger(Dota2PatcherUI.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (javax.swing.UnsupportedLookAndFeelException ex) {
            java.util.logging.Logger.getLogger(Dota2PatcherUI.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        }
        //</editor-fold>

        /* Create and display the form */
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                }
                catch (Exception e) {
                    e.printStackTrace();
                }
                LookAndFeelFactory.installJideExtension();
                new Dota2PatcherUI().setVisible(true);
            }
        });
    }
    
    class VpkManagerWorker extends SwingWorker<VpkManager, VpkManager> {
        int status;
        public VpkManagerWorker (int status) {
            this.status = status;
        }
        protected VpkManager doInBackground() throws Exception {
            try {
                VpkManager vpk = new VpkManager(vpk_path);
                return vpk;
            } catch (Exception e){
                logError(e.getMessage());
            }
            return null;
        }

        protected void done() {
            try {
                vpk = get();
                if (status == 1) {
                   log("VPK Loaded!");
                   jButtonPatch.setEnabled(true);
                }
            } catch (Exception e) {
                logError(e.getMessage());
            }
        }
    }
    
    class FileTraversal {
        public final void traverse( final File f ) throws IOException {
            if (f.isDirectory()) {
                onDirectory(f);
                final File[] childs = f.listFiles();
                for( File child : childs ) {
                        traverse(child);
                }
                return;
            }
            onFile(f);
        }

        public void onDirectory( final File d ) {
        }

        public void onFile( final File f ) {
        }
    }
    
    public class ReturnStatus {
        public String log = null;
        public String type = null;
    }
    
    class Patch extends SwingWorker<List<ReturnStatus>, ReturnStatus> {
        ReturnStatus rs;
        Patch() { 
            //initialize 
        }

        @Override
        public List<ReturnStatus> doInBackground() {
            try {
                updateProgressBar(10);
                logMe("Patching files...", "bold");
                int progress =0;
                if (!files.containsAll(patchedFiles)) {
                    logMe("To remove files we have to rebuild the VPK... Rebuilding..", "blue");
                    revertVpk(0);
                    patchedFiles.clear();
                }
                for(String file: files){                    
                    if (patchedFiles.contains(file.toString()) &&  patchAll == false) {
                        continue;
                    } else if (patchAll == true){
                        progress ++;
                        updateProgressBar((100/files.size())*progress ); 
                    } else {
                        progress ++;
                        updateProgressBar((100/(files.size() - patchedFiles.size()))*progress ); 
                    }
                    patchedFiles.add(file);
                    
                    String path = dp.cleanPath(file.replace(mod_path, ""));
                    logMe(path, "color");
                    if (vpk.extractFile(path, mod_path) == 0) {
                        logMe("Backed up!", "blue");
                    } else {
                        logMe("Could not backup file", "error");
                    }
                    
                    if (vpk.removeFile(path, mod_path) == 0) {
                        logMe("Removed From VPK!", "blue");      
                    } else {
                        logMe("Could not delete file", "error");
                    }
                    updateVpk(0);
                }
                patchAll = false;
                saveTreePaths();
            } catch (Exception e){
                logError(e.getMessage());
            }
            return null;
        }
    /*    
        protected VpkManager refreshVpk() {
            VpkManagerWorker refresh = new VpkManagerWorker(0);
            refresh.execute();
            while (refresh.isDone() == false) {}
            try {
                return refresh.get();
            } catch (InterruptedException ex) {
                Logger.getLogger(Dota2PatcherUI.class.getName()).log(Level.SEVERE, null, ex);
            } catch (ExecutionException ex) {
                Logger.getLogger(Dota2PatcherUI.class.getName()).log(Level.SEVERE, null, ex);
            }
            logMe("Can't refresh vpk.. wtf?", "error");
            return null;
        }
     */   
        protected void done() {
            updateProgressBar(100);
            logBold("Great Success!!");
        }
        
        protected void logMe(String log, String type) {
            rs = new ReturnStatus();
            rs.log = log;
            rs.type = type;
            publish(rs);
        }

        @Override
        protected void process(List<ReturnStatus> chunks) {
            for (ReturnStatus rs : chunks) {
                if (rs.type.equals("error")) {
                    logError(rs.log);
                } else if (rs.type.equals("color")) {
                    logColor(rs.log);
                } else if (rs.type.equals("bold")) {
                    logBold(rs.log);
                } else if (rs.type.equals("blue")) {
                    logBlue(rs.log);
                } else {
                    log(rs.log);
                }

            }
        }
    }

    
    private javax.swing.JFileChooser chooser;
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private com.jidesoft.swing.CheckBoxTree checkBoxTree;
    private javax.swing.JButton jButtonClear;
    private javax.swing.JButton jButtonDota2Path;
    private javax.swing.JButton jButtonExit;
    private javax.swing.JButton jButtonForce;
    private javax.swing.JButton jButtonHelp;
    private javax.swing.JButton jButtonPatch;
    private javax.swing.JButton jButtonVpkPath;
    private javax.swing.JCheckBox jCheckBoxDebug;
    private javax.swing.JLabel jLabel1;
    private javax.swing.JLabel jLabel2;
    private javax.swing.JLabel jLabelDota2Path;
    private javax.swing.JLabel jLabelTop;
    private javax.swing.JProgressBar jProgressBar;
    private javax.swing.JScrollPane jScrollPaneOutput;
    private javax.swing.JScrollPane jScrollPaneTree;
    private javax.swing.JSplitPane jSplitPane2;
    private javax.swing.JTextField jTextDota2Path;
    private javax.swing.JTextField jTextFieldVPKPath;
    private javax.swing.JTextPane jTextPaneOutput;
    // End of variables declaration//GEN-END:variables

}

